#!/usr/bin/env python
# encoding: utf-8
"""
Author: wq
Time: 2022/7/20 17:40
Description:
"""

from django.utils.translation import gettext_lazy as _
from rest_framework import status
from rest_framework.exceptions import Throttled
from rest_framework.throttling import SimpleRateThrottle


class CustomThrottled(Throttled):
    status_code = status.HTTP_429_TOO_MANY_REQUESTS
    default_detail = _("您的请求太过频繁，")
    extra_detail_singular = _("请等待 {wait} 秒后重试.")
    extra_detail_plural = _("请等待 {wait} 秒后重试.")
    default_code = "throttled"


class CustomSimpleRateThrottle(SimpleRateThrottle):
    def get_cache_key(self, request, view):
        pass

    def parse_rate(self, rate):
        """
        Given the request rate string, return a two tuple of:
        <allowed number of requests>, <period of time in seconds>
        """
        if rate is None:
            return (None, None)
        num, period = rate.split("/")
        num_requests = int(num)
        duration = {"s": 1, "m": 60, "h": 3600, "d": 86400}[period[-1]]
        return (num_requests, duration * int(period[:-1]))

    # 直接抛出了一个NotImplementedError，而这样的方法会被Pycharm检测为抽象方法


class AnonRateThrottle(CustomSimpleRateThrottle):
    """
    Limits the rate of API calls that may be made by a anonymous users.

    The IP address of the request will be used as the unique cache key.
    """

    scope = "anon"

    def get_cache_key(self, request, view):
        if request.user.is_authenticated:
            return None  # Only throttle unauthenticated requests.

        return self.cache_format % {"scope": self.scope, "ident": self.get_ident(request)}


class UserRateThrottle(CustomSimpleRateThrottle):
    """
    Limits the rate of API calls that may be made by a given user.

    The user id will be used as a unique cache key if the user is
    authenticated.  For anonymous requests, the IP address of the request will
    be used.
    """

    scope = "user"

    def get_cache_key(self, request, view):
        if request.user.is_authenticated:
            ident = request.user.pk
        else:
            ident = self.get_ident(request)

        return self.cache_format % {"scope": self.scope, "ident": ident}


class ScopedRateThrottle(CustomSimpleRateThrottle):
    """
    Limits the rate of API calls by different amounts for various parts of
    the API.  Any view that has the `throttle_scope` property set will be
    throttled.  The unique cache key will be generated by concatenating the
    user id of the request, and the scope of the view being accessed.
    """

    scope_attr = "throttle_scope"

    def __init__(self):
        # Override the usual SimpleRateThrottle, because we can't determine
        # the rate until called by the view.
        pass

    def allow_request(self, request, view):
        # We can only determine the scope once we're called by the view.
        self.scope = getattr(view, self.scope_attr, None)

        # If a view does not have a `throttle_scope` always allow the request
        if not self.scope:
            return True

        # Determine the allowed request rate as we normally would during
        # the `__init__` call.
        self.rate = self.get_rate()
        self.num_requests, self.duration = self.parse_rate(self.rate)

        # We can now proceed as normal.
        return super().allow_request(request, view)

    def get_cache_key(self, request, view):
        """
        If `view.throttle_scope` is not set, don't apply this throttle.

        Otherwise generate the unique cache key by concatenating the user id
        with the '.throttle_scope` property of the view.
        """
        if request.user.is_authenticated:
            ident = request.user.pk
        else:
            ident = self.get_ident(request)

        return self.cache_format % {"scope": self.scope, "ident": ident}
